// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/speech/audio_buffer.h"

#include "base/logging.h"

namespace content {

AudioChunk::AudioChunk(int bytes_per_sample)
    : bytes_per_sample_(bytes_per_sample)
{
}

AudioChunk::AudioChunk(size_t length, int bytes_per_sample)
    : data_string_(length, '\0')
    , bytes_per_sample_(bytes_per_sample)
{
    DCHECK_EQ(length % bytes_per_sample, 0U);
}

AudioChunk::AudioChunk(const uint8_t* data, size_t length, int bytes_per_sample)
    : data_string_(reinterpret_cast<const char*>(data), length)
    , bytes_per_sample_(bytes_per_sample)
{
    DCHECK_EQ(length % bytes_per_sample, 0U);
}

bool AudioChunk::IsEmpty() const
{
    return data_string_.empty();
}

size_t AudioChunk::NumSamples() const
{
    return data_string_.size() / bytes_per_sample_;
}

const std::string& AudioChunk::AsString() const
{
    return data_string_;
}

int16_t AudioChunk::GetSample16(size_t index) const
{
    DCHECK(index < (data_string_.size() / sizeof(int16_t)));
    return SamplesData16()[index];
}

const int16_t* AudioChunk::SamplesData16() const
{
    return reinterpret_cast<const int16_t*>(data_string_.data());
}

AudioBuffer::AudioBuffer(int bytes_per_sample)
    : bytes_per_sample_(bytes_per_sample)
{
    DCHECK(bytes_per_sample == 1 || bytes_per_sample == 2 || bytes_per_sample == 4);
}

AudioBuffer::~AudioBuffer()
{
    Clear();
}

void AudioBuffer::Enqueue(const uint8_t* data, size_t length)
{
    chunks_.push_back(new AudioChunk(data, length, bytes_per_sample_));
}

scoped_refptr<AudioChunk> AudioBuffer::DequeueSingleChunk()
{
    DCHECK(!chunks_.empty());
    scoped_refptr<AudioChunk> chunk(chunks_.front());
    chunks_.pop_front();
    return chunk;
}

scoped_refptr<AudioChunk> AudioBuffer::DequeueAll()
{
    size_t resulting_length = 0;
    ChunksContainer::const_iterator it;
    // In order to improve performance, calulate in advance the total length
    // and then copy the chunks.
    for (it = chunks_.begin(); it != chunks_.end(); ++it) {
        resulting_length += (*it)->AsString().length();
    }
    scoped_refptr<AudioChunk> chunk(
        new AudioChunk(resulting_length, bytes_per_sample_));
    uint8_t* dest = chunk->writable_data();
    for (it = chunks_.begin(); it != chunks_.end(); ++it) {
        memcpy(dest, (*it)->AsString().data(), (*it)->AsString().length());
        dest += (*it)->AsString().length();
    }
    Clear();
    return chunk;
}

void AudioBuffer::Clear()
{
    chunks_.clear();
}

bool AudioBuffer::IsEmpty() const
{
    return chunks_.empty();
}

} // namespace content
